package worker;

import java.math.BigInteger;
import java.util.Random;

public class RohThread implements Runnable{

    private BigInteger N;
    private BigInteger a;
    private volatile boolean running;
    private Random rand;
    private Worker worker;

    public RohThread(BigInteger N, Worker worker){
        this.a = new BigInteger(5, new Random()).add(BigInteger.ONE);
        this.N = N;
        this.worker = worker;
        rand = new Random();
        running = true;
    }

    //Thread anhalten
    public void stopRoh(){
        running = false;
    }

    public void run() {
        //System.out.println("Starten: RohThread von Worker [ " + worker.getActorId() + " ]; N = " + N);

        int cnt = 0;
        //n = zu faktorisierende Zahl; 
        //a = (worker-basiertes) Inkrement der Zufallssequenz;
        BigInteger p;

        if(N.isProbablePrime(1)){	//wenn bekommene Zahl schon Primzahl ist
            worker.writeMessage(N, N, cnt);
        }else{	//sonst wird Primfaktor berechnet:
            do{
                BigInteger x = new BigInteger(N.bitLength()-1, rand);
                x.add(new BigInteger("1"));

                BigInteger y = x;
                p = new BigInteger("1"); 
                
                //Rohalgorithmus
                do{
                    x = ((x.multiply(x)).add(a)).mod(N); 
                    y = ((y.multiply(y)).add(a)).mod(N); 
                    y = ((y.multiply(y)).add(a)).mod(N);  
                    BigInteger d = (y.subtract(x)).mod(N);

                    p = (d.abs()).gcd(N.abs());
                    cnt++;
                }while(p.equals(new BigInteger("1")) && running);

                if (!p.equals(N) && p.isProbablePrime(1)){	//wenn Primfaktor gefunden
                    //System.out.println("RohThread von Worker [" + worker.getActorId() + "] hat Faktor: " + p);
                	worker.writeMessage(p, N, cnt);	//Msg an den Master schicken
                    running = false;				//Thread beenden
                }

            }while(running);
        }

        //System.out.println("Beendet: RohThread von Worker [ " + worker.getActorId() + " ]; N = " + N);
    }
}
